package com.yycx.module.bus.provider.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yycx.common.base.entity.EntityMap;
import com.yycx.common.base.utils.FlymeUtils;
import com.yycx.common.constants.CommonConstants;
import com.yycx.common.mybatis.base.service.impl.BaseServiceImpl;
import com.yycx.common.mybatis.model.ResultBody;
import com.yycx.common.mybatis.query.CriteriaDelete;
import com.yycx.common.mybatis.query.CriteriaQuery;
import com.yycx.common.mybatis.query.CriteriaSave;
import com.yycx.common.mybatis.query.CriteriaUpdate;
import com.yycx.common.security.OpenHelper;
import com.yycx.common.utils.ApiAssert;
import com.yycx.common.utils.DateUtils;
import com.yycx.common.utils.OrderNoUtil;
import com.yycx.common.utils.SequenceUtils;
import com.yycx.module.bus.client.entity.*;
import com.yycx.module.bus.client.entity.hy.HyOrder;
import com.yycx.module.bus.client.entity.hy.HyOrderDetail;
import com.yycx.module.bus.client.enums.AmountTypeEnum;
import com.yycx.module.bus.client.enums.SaleTypeEnum;
import com.yycx.module.bus.provider.handler.haiying.BusinessUtils;
import com.yycx.module.bus.provider.mapper.BusDepositMapper;
import com.yycx.module.bus.provider.service.*;
import com.yycx.module.file.provider.service.SysFileService;
import com.yycx.module.system.client.entity.SysBank;
import com.yycx.module.system.client.entity.SysCompany;
import com.yycx.module.system.provider.service.SysBankService;
import com.yycx.module.system.provider.service.SysCompanyService;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * 押金管理接口实现类
 *
 * @author flyme
 * @date 2023-07-29
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class BusDepositServiceImpl extends BaseServiceImpl<BusDepositMapper, BusDeposit> implements BusDepositService {

    @Resource
    private SysBankService bankService;

    @Resource
    private BusCustomService customService;

    @Resource
    private BusPaymentService paymentService;

    @Resource
    private SysFileService fileService;

    @Resource
    private SysCompanyService companyService;

    @Resource
    private BusSalemanService salemanService;

    @Resource
    private BusDeptService deptService;

    @Autowired
    private BusinessUtils businessUtils;

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public ResultBody beforePageList(CriteriaQuery<BusDeposit> cq, BusDeposit deposit, EntityMap requestMap) {
        String beginDate = requestMap.get("beginDate");
        String endDate = requestMap.get("endDate");
        cq.select(BusDeposit.class, "*");
        cq.addSelect(BusSaleman.class, "saleManName");
        cq.addSelect(SysBank.class, "bankName", "bankNo");
        cq.like(StrUtil.isNotEmpty(cq.getParams("depositNo")), "depositNo", cq.getParams("depositNo"));
        cq.eq(BusDeposit.class, "customId");
        if (FlymeUtils.isNotEmpty(beginDate)) {
            cq.ge(BusDeposit.class, "payDate", beginDate);
        }
        if (FlymeUtils.isNotEmpty(endDate)) {
            cq.le(BusDeposit.class, "payDate", endDate);
        }
        cq.eq(BusDeposit.class, "companyId", OpenHelper.getCompanyId());
        cq.orderByDesc("deposit.createTime");
        cq.createJoin(SysBank.class);
        cq.createJoin(BusSaleman.class);
        return ResultBody.ok();
    }

    @Override
    public List<EntityMap> afterPageList(CriteriaQuery<BusDeposit> cq, List<EntityMap> data, ResultBody resultBody) {
        for (EntityMap datum : data) {
            Long depositId = datum.getLong("depositId");
            List<EntityMap> fileList = fileService.selectFileList(depositId, BusDeposit.class);
            datum.put("fileList", fileList);
            BusPayment payment = paymentService.getById(depositId);
            if (FlymeUtils.isNotEmpty(payment)) {
                datum.put("paymentState", payment.getPaymentState());
                datum.put("processInstanceId", payment.getProcessInstanceId());
            }
        }
        return super.afterPageList(cq, data, resultBody);
    }

    @Override
    public ResultBody beforeAdd(CriteriaSave cs, BusDeposit deposit, EntityMap extra) {
        Long companyId = OpenHelper.getCompanyId();
        Long userId = OpenHelper.getUserId();
        deposit.setCompanyId(companyId);
        String paymentNo = businessUtils.getPaymentNo(companyId, userId, AmountTypeEnum.DepositAmount);
        deposit.setDepositNo(paymentNo);
        deposit.setDepositId(IdWorker.getId());
        deposit.setDepositState(CommonConstants.INT_0);
        String customCode = cs.getParams("customCode");
        if (FlymeUtils.isNotEmpty(customCode)) {
            BusCustom custom = customService.selectByCustomCode(customCode, companyId);
            SysCompany company = companyService.getById(companyId);
            if (FlymeUtils.isEmpty(custom)) {
                custom = customService.syncBusCustom(company.getBusinessScope(), customCode, companyId);
            }
            if (FlymeUtils.isNotEmpty(custom)) {
                deposit.setCustomId(custom.getCustomId());
            }
        }
        BusPayment payment = paymentService.addBusDepositPayment(deposit);
        deposit.setRkId(payment.getPaymentId());
        return ResultBody.ok();
    }

    @Override
    public ResultBody afterAdd(CriteriaSave cs, BusDeposit busDeposit, EntityMap extra) {
        return super.afterAdd(cs, busDeposit, extra);
    }

    @Override
    public void addDeposit(BusPayment payment) {
        Long companyId = payment.getCompanyId();
        BusDeposit deposit = new BusDeposit();
        BigDecimal amount = payment.getReturnAmount();
        deposit.setCompanyId(companyId);
        deposit.setDepositNo(payment.getPaymentNo());
        deposit.setOrganizationId(payment.getOrganizationId());
        deposit.setSaleManId(payment.getSaleManId());
        deposit.setDepositState(CommonConstants.INT_1);
        deposit.setRkId(payment.getPaymentId());
        deposit.setPayAmount(amount);
        deposit.setDeptId(payment.getDeptId());
        deposit.setPayBankName(payment.getPayBankName());
        deposit.setPayBankNo(payment.getPayBankNo());
        deposit.setPayDate(payment.getAmountDate());
        deposit.setBankId(payment.getBankId());
        saveOrUpdate(deposit);
    }

    @Override
    public void updateDepositState(Long rkId, Integer depositState) {
        CriteriaUpdate cu = new CriteriaUpdate();
        cu.set(true, "depositState", depositState);
        cu.eq(true, "rkId", rkId);
        update(cu);
    }

    @Override
    public void afterGet(CriteriaQuery cq, EntityMap result) {
        Long customId = result.getLong("customId");
        if (FlymeUtils.isNotEmpty(customId)) {
            BusCustom custom = customService.getById(customId);
            if (FlymeUtils.isNotEmpty(custom)) {
                result.put("customName", custom.getCustomName());
            }
        }
        Long saleManId = result.getLong("saleManId");
        if (FlymeUtils.isNotEmpty(saleManId)) {
            BusSaleman saleman = salemanService.getById(saleManId);
            if (FlymeUtils.isNotEmpty(saleman)) {
                result.put("saleManName", saleman.getSaleManName());
            }
        }
        Long deptId = result.getLong("deptId");
        if (FlymeUtils.isNotEmpty(deptId)) {
            BusDept dept = deptService.getById(deptId);
            if (FlymeUtils.isNotEmpty(dept)) {
                result.put("deptName", dept.getDeptName());
            }
        }
        Long bankId = result.getLong("bankId");
        if (FlymeUtils.isNotEmpty(bankId)) {
            SysBank bank = bankService.getById(bankId);
            if (FlymeUtils.isNotEmpty(bank)) {
                result.put("bankName", bank.getBankName());
            }
        }
        super.afterGet(cq, result);
    }

    @Override
    public ResultBody beforeEdit(CriteriaUpdate<BusDeposit> cu, BusDeposit busDeposit, EntityMap extra) {

        return super.beforeEdit(cu, busDeposit, extra);
    }

    @Override
    public ResultBody afterEdit(CriteriaUpdate cu, BusDeposit busDeposit, EntityMap extra) {
        paymentService.addBusDepositPayment(busDeposit);
        return super.afterEdit(cu, busDeposit, extra);
    }


    @Override
    public ResultBody afterDelete(CriteriaDelete cd, Serializable[] ids) {
        Serializable id = cd.getIdValue();
        if (FlymeUtils.isNotEmpty(id)) {
            paymentService.removeByOrderId(AmountTypeEnum.DepositAmount, id.toString());
        }
        return super.afterDelete(cd, ids);
    }


    @Override
    public ResultBody refundAmount(Map params) {
        ApiAssert.isNotEmpty("Id不能为空", params.get("depositId"));
        BusDeposit busDeposit = this.getById(MapUtil.getLong(params, "depositId"));
        this.update(new UpdateWrapper<BusDeposit>().lambda().eq(BusDeposit::getDepositId, busDeposit.getDepositId()).set(BusDeposit::getRefundDate, MapUtil.getStr(params, "refundDate")).set(BusDeposit::getRefundAmount, new BigDecimal(MapUtil.getStr(params, "refundAmount"))));
        return ResultBody.ok();
    }

    @Override
    public boolean updateRefundId(Long paymentId, Long depositId) {
        CriteriaUpdate cu = new CriteriaUpdate();
        cu.set(true, "refundId", paymentId);
        cu.eq(true, "depositId", depositId);
        return update(cu);
    }

    @Override
    public boolean clearRefundId(Serializable paymentId) {
        if (FlymeUtils.allNotNull(paymentId)) {
            CriteriaUpdate cu = new CriteriaUpdate();
            cu.set(true, "refundId", null);
            cu.eq(true, "refundId", paymentId);
            update(cu);
        }
        return true;
    }


    /**
     * 按月从001开始生成序列号
     */
    private String getOrderNo(Long companyId) {
        //加锁避免重复
        RLock lock = redisLock.lock(companyId);
        String result = null;
        try {
            String yyyyMM = DateUtils.formatDate(DateUtils.getNowDate(), "yyyyMM");
            CriteriaQuery<BusDeposit> cq = new CriteriaQuery(BusDeposit.class);
            cq.select("depositNo");
            cq.eq(true, "companyId", companyId);
            cq.likeRight(true, "depositNo", yyyyMM);
            Long count = count(cq);
            String date = DateUtils.formatDate(DateUtils.getNowDate(), "MMdd");
            String year = DateUtils.getYear();
            String firstNo = year + date + "001";
            if (count.equals(0L)) {
                return firstNo;
            }
            String orderNo = String.format("%03d", count.intValue() + 1);
            result = year + date + orderNo;
        } finally {
            redisLock.unlock(lock);
        }
        return result;
    }

    @Override
    public boolean updateRefund(BusPayment payment) {
        Long refundId = payment.getPaymentId();
        CriteriaUpdate cu = new CriteriaUpdate();
        cu.set(true, "refundAmount", payment.getAmount());
        cu.set(true, "refundDate", payment.getPayDate());
        cu.set(true, "deductAmount", payment.getReturnAmount());
        cu.set(true, "depositState", CommonConstants.INT_1);
        cu.eq(true, "refundId", refundId);
        return update(cu);
    }

    public BusDeposit findBySaleManId(Long saleManId, Long companyId) {
        CriteriaQuery cq = new CriteriaQuery(BusDeposit.class);
        cq.eq(true, "saleManId", saleManId);
        cq.eq(true, "companyId", companyId);
        return getOne(cq, false);
    }

}
